<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>grid实现瀑布流</title>
  <style>
    body {
      margin: 0;
    }
    .masonry {
      --row-height: 5px;  /* 若设为1px，网格过多，性能是否有问题？*/
      --row-gap: 10px;
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      grid-gap: 0 20px;
      grid-auto-rows: var(--row-height);
      align-items: end;
    }
    .item {
      background: #f8f8fa;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    @media (min-width: 1280px) and (max-width: 1920px) {
      .masonry {
        grid-template-columns: repeat(3, 1fr);
      }
    }
    @media (min-width: 768px) and (max-width: 1280px) {
      .masonry {
        grid-template-columns: repeat(2, 1fr);
      }
    }
    @media (max-width: 768px) {
      .masonry {
        grid-template-columns: repeat(1, 1fr);
      }
    }
  </style>
</head>
<body>
  <div class="masonry">
    <div class="item">item1</div>
    <div class="item">item2</div>
    <div class="item">item3</div>
    <div class="item">item4</div>
    <div class="item">item5</div>
    <div class="item">item6</div>
    <div class="item">item7</div>
    <div class="item">item8</div>
    <div class="item">item9</div>
    <div class="item">item10</div>
    <div class="item">item11</div>
    <div class="item">item12</div>
    <div class="item">item13</div>
    <div class="item">item14</div>
    <div class="item">item15</div>
    <div class="item">item16</div>
    <div class="item">item17</div>
    <div class="item">item18</div>
    <div class="item">item19</div>
    <div class="item">item20</div>
    <div class="item">item21</div>
    <div class="item">item22</div>
    <div class="item">item23</div>
    <div class="item">item24</div>
    <div class="item">item25</div>
  </div>

  <script>
    // 给每个元素模拟随机高度
    window.addEventListener('load', () => {
      document.querySelectorAll('.masonry > .item').forEach(item => {
        item.style.height = `${Math.floor(Math.random() * 200) + 100}px`
      })
    })

    const calcRows = () => {
      const masonry = document.querySelector('.masonry')
      const items = masonry.querySelectorAll('.item')
      const style = getComputedStyle(masonry)
      const rowHeight = parseInt(style.getPropertyValue('--row-height'));
      const gap = parseInt(style.getPropertyValue('--row-gap'));
      // 获取当前列数
      const cols = style.gridTemplateColumns.split(" ").length;
      items.forEach((item, index) => {
        // 给需要上下间隔的元素增加上间隔（每列第一个元素无需上间隔）
        const gapRows = index >= cols ? gap/rowHeight : 0;
        // 根据元素高度设置元素的需占行数
        const rows = Math.ceil(item.clientHeight / rowHeight) + gapRows;
        item.style.gridRowEnd = `span ${rows}`;
      })
    }

    window.addEventListener('resize', calcRows)
    window.addEventListener('load', calcRows)
  </script>
</body>
</html>
